home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / KERNEL.C < prev    next >
C/C++ Source or Header  |  1989-09-07  |  12KB  |  489 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion */
  2. #if    defined(PROCLOG) || defined(PROCTRACE)
  3. #include <stdio.h>
  4. #endif
  5. #include <dos.h>
  6. #include <setjmp.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "proc.h"
  10. #include "timer.h"
  11. #include "socket.h"
  12. #ifdef    MSDOS
  13. #include "pc.h"
  14. #endif
  15.  
  16. #ifdef    PROCLOG
  17. FILE *proclog;
  18. FILE *proctrace;
  19. #endif
  20. int Stkchk = 0;
  21. struct proc *Curproc;        /* Currently running process */
  22. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  23. struct proc *Waittab[PHASH];    /* Waiting process list */
  24. struct proc *Susptab;        /* Suspended processes */
  25. static struct mbuf *Killq;
  26.  
  27. static void addproc __ARGS((struct proc *entry));
  28. static void delproc __ARGS((struct proc *entry));
  29. static unsigned phash __ARGS((void *event));
  30.  
  31. /* Create a process descriptor for the main function. Must be actually
  32.  * called from the main function!
  33.  */
  34. struct proc *
  35. mainproc(name)
  36. char *name;
  37. {
  38.     register struct proc *pp;
  39.  
  40.     /* Create process descriptor */
  41.     if((pp = (struct proc *)calloc(1,sizeof(struct proc))) == NULLPROC)
  42.         return NULLPROC;
  43.  
  44.     /* Create name */
  45.     pp->name = strdup(name);
  46. #ifndef    AMIGA
  47.     pp->stksize = 65535;
  48.     psetup(pp,0,NULL,NULL,NULLVFP);
  49. #else
  50.     init_psetup(pp);
  51. #endif
  52.     /* Make current */
  53.     pp->state = READY;
  54.     Curproc = pp;
  55.  
  56. #ifdef    PROCLOG
  57.     proclog = fopen("proclog",APPEND_TEXT);
  58.     proctrace = fopen("proctrace",APPEND_TEXT);
  59. #endif
  60.     return pp;
  61. }
  62. /* Create a new, ready process and return pointer to descriptor.
  63.  * The general registers are not initialized, but optional args are pushed
  64.  * on the stack so they can be seen by a C function.
  65.  */
  66. struct proc *
  67. newproc(name,stksize,pc,iarg,parg1,parg2)
  68. char *name;        /* Arbitrary user-assigned name string */
  69. unsigned int stksize;    /* Stack size in words to allocate */
  70. void (*pc)();        /* Initial execution address */
  71. int iarg;        /* Integer argument (argc) */
  72. void *parg1;        /* Generic pointer argument #1 (argv) */
  73. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  74. {
  75.     register struct proc *pp;
  76.     int i;
  77.  
  78.     if(Stkchk)
  79.         chkstk();
  80.  
  81.     /* Create process descriptor */
  82.     if((pp = (struct proc *)calloc(1,sizeof(struct proc))) == NULLPROC)
  83.         return NULLPROC;
  84.  
  85.     /* Create name */
  86.     pp->name = strdup(name);
  87.  
  88.     /* Allocate stack */
  89. #ifdef    AMIGA
  90.     stksize += 2000;    /* DOS overhead */
  91. #endif
  92.     pp->stksize = stksize;
  93.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  94.         free(pp->name);
  95.         free((char *)pp);
  96.         return NULLPROC;
  97.     }
  98.     /* Initialize stack for high-water check */
  99.     for(i=0;i<stksize;i++)
  100.         pp->stack[i] = STACKPAT;
  101.  
  102.     /* Do machine-dependent initialization of stack */
  103.     psetup(pp,iarg,parg1,parg2,pc);
  104.  
  105.     /* Add to ready process table */
  106.     pp->state = READY;
  107.     addproc(pp);
  108.     return pp;
  109. }
  110.  
  111. /* Free resources allocated to specified process. If a process wants to kill
  112.  * itself, the reaper is called to do the dirty work. This avoids some
  113.  * messy situations that would otherwise occur, like freeing your own stack.
  114.  */
  115. void
  116. killproc(pp)
  117. register struct proc *pp;
  118. {
  119.     if(pp == NULLPROC)
  120.         return;
  121.     /* Don't check the stack here! Will cause infinite recursion if
  122.      * called from a stack error
  123.      */
  124.  
  125.     if(pp == Curproc)
  126.         killself();    /* Doesn't return */
  127.  
  128.     /* Close any open sockets */
  129.     freesock(pp);
  130.  
  131.     /* Stop alarm clock in case it's running */
  132.     stop_timer(&pp->alarm);
  133.  
  134.     /* Alert everyone waiting for this proc to die */
  135.     psignal(pp,0);
  136.  
  137.     /* Remove from appropriate table */
  138.     delproc(pp);
  139.  
  140. #ifdef    PROCLOG
  141.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  142.         pp->name,stkutil(pp),pp->stksize);
  143.     fclose(proclog);
  144.     proclog = fopen("proclog",APPEND_TEXT);
  145.     proctrace = fopen("proctrace",APPEND_TEXT);
  146. #endif
  147.     /* Free allocated memory resources */
  148.     free(pp->name);
  149.     free(pp->stack);
  150.     free((char *)pp);
  151. }
  152. /* Terminate current process by sending a request to the killer process.
  153.  * Automatically called when a process function returns. Does not return.
  154.  */
  155. void
  156. killself()
  157. {
  158.     register struct mbuf *bp;
  159.  
  160.     if(Curproc != NULLPROC){
  161.         bp = pushdown(NULLBUF,sizeof(Curproc));
  162.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  163.         enqueue(&Killq,bp);
  164.     }
  165.     /* "Wait for me; I will be merciful and quick." */
  166.     for(;;)
  167.         pwait(NULL);
  168. }
  169. /* Process used by processes that want to kill themselves */
  170. void
  171. killer(i,v1,v2)
  172. int i;
  173. void *v1;
  174. void *v2;
  175. {
  176.     struct proc *pp;
  177.     struct mbuf *bp;
  178.  
  179.     for(;;){
  180.         while(Killq == NULLBUF)
  181.             pwait(&Killq);
  182.         bp = dequeue(&Killq);
  183.         pullup(&bp,(char *)&pp,sizeof(pp));
  184.         free_p(bp);
  185.         if(pp != Curproc)    /* We're immortal */
  186.             killproc(pp);
  187.     }                        
  188. }
  189.  
  190. #ifdef    notused
  191. /* Inhibit a process from running */
  192. static void
  193. suspend(pp)
  194. struct proc *pp;
  195. {
  196.     if(pp == NULLPROC)
  197.         return;
  198.     if(pp != Curproc)
  199.         delproc(pp);    /* Running process isn't on any list */
  200.     pp->state |= SUSPEND;
  201.     if(pp != Curproc)
  202.         addproc(pp);    /* pwait will do it for us */
  203.     else
  204.         pwait(NULL);
  205. }
  206. /* Restart suspended process */
  207. static void
  208. resume(pp)
  209. struct proc *pp;
  210. {
  211.     if(pp == NULLPROC)
  212.         return;
  213.     delproc(pp);    /* Can't be Curproc! */
  214.     pp->state &= ~SUSPEND;
  215.     addproc(pp);
  216. }
  217. #endif    /* notused */
  218.  
  219. /* Wakeup waiting process, regardless of event it's waiting for. The process
  220.  * will see a return value of "val" from its pwait() call.
  221.  */
  222. void
  223. alert(pp,val)
  224. struct proc *pp;
  225. int val;
  226. {
  227.     if(pp == NULLPROC)
  228.         return;
  229.     if((pp->state & WAITING) == 0)
  230.         return;
  231. #ifdef    PROCTRACE
  232.     printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  233.     fflush(stdout);
  234. #endif
  235.     if(pp != Curproc)
  236.         delproc(pp);
  237.     pp->state &= ~WAITING;
  238.     pp->retval = val;
  239.     pp->event = 0;
  240.     addproc(pp);
  241. }
  242.  
  243. /* Post a wait on a specified event and give up the CPU until it happens. The
  244.  * null event is special: it means "I don't want to block on an event, but let
  245.  * somebody else run for a while". It can also mean that the present process
  246.  * is terminating; in this case the wait never returns.
  247.  *
  248.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  249.  * arg in an alert() call. Pwait must not be called from interrupt level.
  250.  */
  251. int
  252. pwait(event)
  253. void *event;
  254. {
  255.     struct proc *oldproc;
  256.     char i_state;
  257.     int tmp;
  258.  
  259.     i_state = dirps();
  260.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  261.         if(Stkchk)
  262.             chkstk();
  263.  
  264.         if(event == NULL){
  265.             /* Special case; just give up the processor.
  266.              *
  267.              * Optimization: if nothing else is ready, just return.
  268.              */
  269.             if(Rdytab == NULLPROC){
  270.                 restore(i_state);
  271.                 return 0;
  272.             }
  273.         } else {
  274.             /* Post a wait for the specified event */
  275.             Curproc->event = event;
  276.             Curproc->state = WAITING;
  277.         }
  278.         addproc(Curproc);
  279.     }
  280.     /* Look for a ready process and run it. If there are none,
  281.      * loop or halt until an interrupt makes something ready.
  282.      */
  283.     while(Rdytab == NULLPROC){
  284.         /* give system back to upper-level multitasker, if any */
  285.         giveup();
  286.     }
  287.     /* Remove first entry from ready list */
  288.     oldproc = Curproc;
  289.     Curproc = Rdytab;
  290.     delproc(Curproc);
  291.  
  292.     /* Now do the context switch.
  293.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  294.      *
  295.      * If the old process has gone away, simply load the new process's
  296.      * environment. Otherwise, save the current process's state. Then if
  297.      * this is still the old process, load the new environment. Since the
  298.      * new task will "think" it's returning from the setjmp() with a return
  299.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  300.      * would otherwise cause an infinite loop.
  301.      */
  302. #ifdef    PROCTRACE
  303.     if(strcmp(oldproc->name,Curproc->name) != 0){
  304.           printf("-> %s(%d)\n",Curproc->name,Curproc->i_state);
  305.         fflush(stdout);
  306.     }
  307. #endif
  308.     /* Note use of comma operator to save old interrupt state only if
  309.      * oldproc is non-null
  310.      */
  311.     if(oldproc == NULLPROC
  312.      || (oldproc->i_state = i_state, setjmp(oldproc->env) == 0)){
  313.         /* We're still running in the old task; load new task context.
  314.          * The interrupt state is restored here in case longjmp
  315.          * doesn't do it (e.g., systems other than Turbo-C).
  316.          */
  317.         restore(Curproc->i_state);
  318.         longjmp(Curproc->env,1);
  319.     }
  320.     /* At this point, we're running in the newly dispatched task */
  321.     tmp = Curproc->retval;
  322.     Curproc->retval = 0;
  323.  
  324.     /* Also restore the true interrupt state here, in case the longjmp
  325.      * DOES restore the interrupt state saved at the time of the setjmp().
  326.      * This is the case with Turbo-C's setjmp/longjmp.
  327.      */
  328.     restore(Curproc->i_state);
  329.     return tmp;
  330. }
  331.  
  332. /* Make ready the first 'n' processes waiting for a given event. The ready
  333.  * processes will see a return value of 0 from pwait().  Note that they don't
  334.  * actually get control until we explicitly give up the CPU ourselves through
  335.  * a pwait(). Psignal may be called from interrupt level.
  336.  */
  337. void
  338. psignal(event,n)
  339. void *event;    /* Event to signal */
  340. int n;        /* Max number of processes to wake up */
  341. {
  342.     register struct proc *pp;
  343.     struct proc *pnext;
  344.     int i_state;
  345.  
  346.     if(Stkchk)
  347.         chkstk();
  348.  
  349.     if(event == NULL)
  350.         return;        /* Null events are invalid */
  351.  
  352.     /* n = 0 means "signal everybody waiting for this event" */
  353.     if(n == 0)
  354.         n = 65535;
  355.  
  356.     i_state = dirps();
  357.     for(pp = Waittab[phash(event)];n != 0 && pp != NULLPROC;pp = pnext){
  358.         pnext = pp->next;
  359.         if(pp->event == event){
  360. #ifdef    PROCTRACE
  361.             if(i_state){
  362.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  363.                  ptol(pp),pp->name);
  364.                 fflush(stdout);
  365.             }
  366. #endif
  367.             delproc(pp);
  368.             pp->state &= ~WAITING;
  369.             pp->event = 0;
  370.             pp->retval = 0;
  371.             n--;
  372.             addproc(pp);
  373.         }
  374.     }
  375.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  376.         pnext = pp->next;
  377.         if(pp->event == event){
  378. #ifdef    PROCTRACE
  379.             if(i_state){
  380.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  381.                  ptol(pp),pp->name);
  382.                 fflush(stdout);
  383.             }
  384. #endif
  385.             delproc(pp);
  386.             pp->state &= ~WAITING;
  387.             pp->event = 0;
  388.             pp->retval = 0;
  389.             addproc(pp);
  390.             n--;
  391.         }
  392.     }
  393.     restore(i_state);
  394. }
  395.  
  396. /* Rename a process */
  397. void
  398. chname(pp,newname)
  399. struct proc *pp;
  400. char *newname;
  401. {
  402.     free(pp->name);
  403.     pp->name = strdup(newname);
  404. }
  405. /* Remove a process entry from the appropriate table */
  406. static void
  407. delproc(entry)
  408. register struct proc *entry;    /* Pointer to entry */
  409. {
  410.     int i_state;
  411.  
  412.     if(entry == NULLPROC)
  413.         return;
  414.  
  415.     i_state = dirps();
  416.     if(entry->next != NULLPROC)
  417.         entry->next->prev = entry->prev;
  418.     if(entry->prev != NULLPROC)
  419.         entry->prev->next = entry->next;
  420.     else {
  421.         switch(entry->state){
  422.         case READY:
  423.             Rdytab = entry->next;
  424.             break;
  425.         case WAITING:
  426.             Waittab[phash(entry->event)] = entry->next;
  427.             break;
  428.         case SUSPEND:
  429.         case SUSPEND|WAITING:
  430.             Susptab = entry->next;
  431.             break;
  432.         }
  433.     }
  434.     restore(i_state);
  435. }
  436. /* Append proc entry to end of appropriate list */
  437. static void
  438. addproc(entry)
  439. register struct proc *entry;    /* Pointer to entry */
  440. {
  441.     register struct proc *pp;
  442.     struct proc **head;
  443.     int i_state;
  444.  
  445.     if(entry == NULLPROC)
  446.         return;
  447.  
  448.     i_state = dirps();
  449.     switch(entry->state){
  450.     case READY:
  451.         head = &Rdytab;
  452.         break;
  453.     case WAITING:
  454.         head = &Waittab[phash(entry->event)];
  455.         break;
  456.     case SUSPEND:
  457.     case SUSPEND|WAITING:
  458.         head = &Susptab;
  459.         break;
  460.     }
  461.     entry->next = NULLPROC;
  462.     if(*head == NULLPROC){
  463.         /* Empty list, stick at beginning */
  464.         entry->prev = NULLPROC;
  465.         *head = entry;
  466.     } else {
  467.         /* Find last entry on list */
  468.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  469.             ;
  470.         pp->next = entry;
  471.         entry->prev = pp;
  472.     }
  473.     restore(i_state);
  474. }
  475. static unsigned
  476. phash(event)
  477. void *event;
  478. {
  479.     register char *cp = (char *)&event;
  480.     int i = sizeof(event);
  481.     register unsigned x = 0;
  482.  
  483.     while(i-- != 0)
  484.         x ^= *cp++;
  485.  
  486.     return x % PHASH;
  487. }
  488.  
  489.